package jwlee.testthread;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 自拿自取的同步
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright:  Copyright (c) 2010</p>
 * <p>Company: DC </p>
 * 
 * @author lijwg
 * @date 2011-11-23
 * @version 1.0
 */
public class TakeItSelf{
	private WorkArea wa = new MyWorkArea();
	private Set<String> paramSet = new HashSet<String>();
	private int time;
	private static int testtime = 500;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TakeItSelf outer = new TakeItSelf();
		for(int i=0;i<testtime;i++){
			new Thread(outer.new Invoker(i)).start();
		}
//		synchronized (outer) {
//			System.out.println("stop!");
//			if (outer.wa.currT != null) {
//				outer.wa.currT.notify();
//				outer.wa.currT = null;
//			}
//			outer.wa.markQueue.clear();
//		}
	}

	/**
	 * 调用者
	 */
	class Invoker implements Runnable{
		private int val = 0;//参数
		
		Invoker(int val){
			this.val = val;
		}

		@Override
		public void run() {
			String param = this.execute();
			//结果判断
			System.out.println("--------result: " + param);
			if(paramSet.contains(param)){
				System.err.println(param + " already exists!!!");//如果没有已经出现的则同步成功
				System.exit(0);
			} else {
				paramSet.add(param);
			}
		}

		//具体操作
		private String execute() {
			//1. set
			wa.setParam(String.valueOf(val));
			//2. 模拟其他操作
			try {
				Thread.sleep(5);
			} catch (InterruptedException e) {
			}
			//3. get
			String param = wa.getParam();
			return param;
		}
	}
	
	/**
	 * 工作区
	 */
	class WorkArea{
		protected String param;//存放参数
		
		public void setParam(String param) {
			synchronized (this) {
//				System.out.println("set()... " + param);
				this.param = param;
			}
		}

		public String getParam() {
//			System.out.println("get()... " + param);
			return param;
		}
	}
	
	/**
	 * 实现同步，旨在将setter和getter捏成一个原子操作
	 * 利用将每个线程的参数缓存起来
	 */
	class MyWorkArea extends WorkArea{
		//存放每个线程的参数
		private Map<Thread,String> paramMap = new HashMap<Thread,String>();
		public void setParam(String param) {
			synchronized (this) {
				super.setParam(param);
				paramMap.put(Thread.currentThread(), param);
			}
		}

		public String getParam() {
			synchronized (this) {
				String param = paramMap.get(Thread.currentThread());
				if(param != null){
					paramMap.remove(Thread.currentThread());
					return param;
				}
				return super.getParam();
			}
		}
	}
	/**
	 * 实现同步，旨在将setter和getter捏成一个原子操作
	 * 利用同步队列
	 */
	class MyWorkArea2 extends WorkArea{
		private Queue<Thread> waitQueue = new LinkedBlockingQueue<Thread>(testtime);//等待线程队列
		private Thread currT;//当前执行线程：null (setter) T (getter) null
		
		public void setParam(String param) {
			synchronized (this) {
				System.out.println("set()... " + currT);
				Thread currT = Thread.currentThread();
				System.out.println("set(" + param + ")... " + currT);
				synchronized (currT){
					if(this.currT != null){
						waitQueue.add(currT);
						System.out.println(currT + " wait");
						try {
							currT.wait();
						} catch (Exception e) {
							System.err.println(currT + " wait " + e);
						}
					}
					System.out.println("time: " + time++);
					this.currT = currT;
					this.param = param;
				}
			}
		}

		public String getParam() {
			Thread currT = Thread.currentThread();
			System.out.println("get()... " + currT + " time=" + time);
			Thread mark = waitQueue.peek();
			if (mark != null) {
				synchronized (mark) {
					System.out.println(mark + " notify");
					try {
						this.currT = null;
						return param;
					} catch (Exception e) {
						System.err.println(mark + "," + e.getMessage());
					} finally{
						waitQueue.poll().notify();
					}
				}
			}
			this.currT = null;
			return param;
		}
	}
}

